#include "MsgManage.h"
#include "gtime.h"
#include <QtMath>
#include "ShipManage.h"
#include "dbalertlog.h"
#include "mylogger.h"
#include "MsgParser.h"
#include <QDebug>
#include "deviceType.h"

using namespace ns_yht;
using namespace AlertType;

MsgManage *MsgManage::g_manage = nullptr;

namespace
{
    const int shape_point = 0;
    const int shape_line = 1;
    const int shape_polygon = 2;
    const int shape_circle = 3;
}

Q_DECLARE_METATYPE(ModelShip *)

MsgManage::MsgManage()
{
    g_manage = this;
    m_listMessage[0] = (QVector<QSharedPointer<ModelMsg>>());
    m_listMessage[1] = (QVector<QSharedPointer<ModelMsg>>());
    m_listMessage[2] = (QVector<QSharedPointer<ModelMsg>>());

    m_timerId = startTimer(120000); // 每2分钟保存一次
}

MsgManage::~MsgManage()
{
    if (m_timerId > 0)
        killTimer(m_timerId);
    g_manage = nullptr;
    DbAlertLog db;
    db.removeBefore(GTime::getUtcTime_s() - 864000 * 3 * 12); // 删除3*10天前的数据  10 * 24 * 60 * 60 * 3
    save();
}

MsgManage *MsgManage::instance()
{
    if (!g_manage)
        new MsgManage;
    return g_manage;
}

void MsgManage::bindSignals()
{
    if (!SHIPMANAGE)
        return;
    connect(MSGPARSER, &MsgParser::deviceLost, this, &MsgManage::appendDeviceLose);
    connect(MSGPARSER, &MsgParser::deviceRecovered, this, &MsgManage::recoverDevice);
    connect(SHIPMANAGE, &ShipManage::shipCollisionAlarm, this, &MsgManage::appendDangerousShip);
    connect(SHIPMANAGE, &ShipManage::cancelShipCollision, this, &MsgManage::cancelDangerousShip);
    connect(SHIPMANAGE, &ShipManage::autoShipCollision, this, &MsgManage::autoDangerousShip);
    connect(SHIPMANAGE, &ShipManage::cancelAllShipCollision, this, &MsgManage::cancelAllShipCollision);
    connect(this, &MsgManage::ensureToShipManage, SHIPMANAGE, &ShipManage::ensure);
}

const QVector<QSharedPointer<ModelMsg>> &MsgManage::msgList(int level) const
{
    if (level < AlertLevel::caution || level > AlertLevel::alarm)
        return m_listMessage[0];
    return m_listMessage[level];
}

int MsgManage::getCount(int level) const
{
    if (level < AlertLevel::caution || level > AlertLevel::alarm)
        return 0;
    int count = 0;
    for (auto msg : m_listMessage[level])
    {
        if (!msg->expired && !msg->isEnsured)
            count++;
    }
    return count;
}

void MsgManage::appendEFenceMsg(const QString &msg)
{
    QSharedPointer<ModelMsg> model(new ModelMsg);
    model->type = type_efence;
    model->msg = msg;
    model->time = GTime::getUtcTime_s();
    int level = getLevel(model->type);
    m_listMessage[level].insert(0, model);
    m_msgIndex[level] = 0;
    emit newMsg(model.data());
}

void MsgManage::appendDangerousShip(quint64 mmsi, double tcpa, QString name, bool emergency)
{
    const int ctype = emergency ? type_shipCollision : type_shipCollision_low;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype, mmsi);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        if (model->isEnsured)
            return;

        // if (emergency && ((GTime::getUtcTime_s() - model->time) > 15))
        // {
        //     // 调用外部喇叭报警
        //     emit emergencyAlarm();
        // }
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = ctype;
        model->shapeType = shape_point;
        model->ID = mmsi;
        model->isEnsured = false;
        int level = getLevel(model->type);
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
        model->time = GTime::getUtcTime_s(); // 原来放在大括号下面，用于表示最新提示时间；yhtc需要判断紧急报警一定时间没有确认后提高报警音量，故只记录生成时间
    }

    int m = qFloor(tcpa);
    int s = qRound((tcpa - m) * 60);
    if (m == 0 && s == 0)
    {
        model->msg = QString("已经与船舶[%1]相遇，注意避让！").arg(name);
    }
    else
    {
        QString str;
        if (s == 0)
            str = QString("%1分钟").arg(m, 2, 10, QChar('0'));
        else
            str = QString("%1分%2秒").arg(m, 2, 10, QChar('0')).arg(s, 2, 10, QChar('0'));
        model->msg = QString("%1后将与船舶[%2]相遇！").arg(str).arg(name);
    }

    emit newMsg(model.data());
}

void MsgManage::cancelDangerousShip(quint64 mmsi, bool emergency)
{
    const int ctype = emergency ? type_shipCollision : type_shipCollision_low;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype, mmsi);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

// 黑匣子专用，目前提示信息固定，所以不需要语句提示
void MsgManage::autoDangerousShip(quint64 mmsi, bool isEnsure)
{
    const int ctype = type_shipCollision;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype, mmsi);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        if (!model->isEnsured)
        {
            model->isEnsured = isEnsure;
            model->ensureTime = GTime::getUtcTime_s();
        }
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = ctype;
        model->shapeType = shape_point;
        model->ID = mmsi;
        model->isEnsured = false;
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = -1;
        model->time = GTime::getUtcTime_s(); // 原来放在大括号下面，用于表示最新提示时间；yhtc需要判断紧急报警一定时间没有确认后提高报警音量，故只记录生成时间
    }
}

void MsgManage::cancelAllShipCollision()
{
    const int ctype = type_shipCollision;
    int level = getLevel(ctype);
    for (auto model : m_listMessage[level])
    {
        if (model->type == ctype && !model->expired)
        {
            model->expired = true;
            model->expiredTime = GTime::getUtcTime_s();
        }
    }
}

void MsgManage::appendAnchorDragging()
{
    int level = getLevel(type_anchorDragging);
    int index = findMsg(level, type_anchorDragging);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_anchorDragging;
        model->shapeType = shape_point;
        model->msg = QString("船舶发生走锚！");
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::cancelAnchorDragging()
{
    int level = getLevel(type_anchorDragging);
    int index = findMsg(level, type_anchorDragging);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendOffroute()
{
    int level = getLevel(type_offroute);
    int index = findMsg(level, type_offroute);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_offroute;
        model->shapeType = shape_point;
        model->msg = QString("船舶偏离航线!");
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::cancelOffroute()
{
    int level = getLevel(type_offroute);
    int index = findMsg(level, type_offroute);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendOffrouteCourse()
{
    int level = getLevel(type_offrouteCourse);
    int index = findMsg(level, type_offrouteCourse);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_offrouteCourse;
        model->shapeType = shape_point;
        model->msg = QString("船舶偏离航向！");
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::cancelOffrouteCourse()
{
    int level = getLevel(type_offrouteCourse);
    int index = findMsg(level, type_offrouteCourse);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendPoiAlarm(int poiType)
{
    if (poiType == 0)
        return;
    int level = getLevel(type_poi_alarm);
    int index = findMsg(level, type_poi_alarm);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_poi_alarm;
        // model->shapeType = shape_point;

        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    QString spoi;
    if (poiType & AlertPoiType::dangerousObject)
        spoi = "危险物";
    if (poiType & AlertPoiType::navMark)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "航标";
    }
    if (poiType & AlertPoiType::safetyContour)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "安全等深线";
    }
    if (poiType & AlertPoiType::land)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "陆地";
    }
    model->msg = QString("船舶前方有：【%1】").arg(spoi);
    model->time = GTime::getUtcTime_s();

    emit newMsg(model.data());
}

void MsgManage::cancelPoiAlarm()
{
    int level = getLevel(type_poi_alarm);
    int index = findMsg(level, type_poi_alarm);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendPoiWarning(int poiType)
{
    if (poiType == 0)
        return;
    int level = getLevel(type_poi_warning);
    int index = findMsg(level, type_poi_warning);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_poi_warning;
        // model->shapeType = shape_point;
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    QString spoi;
    if (poiType & AlertPoiType::channelSeperate)
        spoi = "通航分隔带";
    if (poiType & AlertPoiType::alongChannel)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "近岸交通区"; //"沿岸通航带";
    }
    if (poiType & AlertPoiType::careful)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "警告区";
    }
    if (poiType & AlertPoiType::military)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "军事演习区域";
    }
    if (poiType & AlertPoiType::airport)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "海上飞机起降区";
    }
    if (poiType & AlertPoiType::anchor)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "锚地区";
    }
    if (poiType & AlertPoiType::farm)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "海上养殖场";
    }
    if (poiType & AlertPoiType::limit)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "限制区";
    }
    if (poiType & AlertPoiType::diving)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "潜水艇航道";
    }
    if (poiType & AlertPoiType::production)
    {
        if (!spoi.isEmpty())
            spoi += "、";
        spoi += "海上作业区";
    }

    model->msg = QString("船舶前方有：【%1】").arg(spoi);
    model->time = GTime::getUtcTime_s();
    emit newMsg(model.data());
}

void MsgManage::cancelPoiWarning()
{
    int level = getLevel(type_poi_warning);
    int index = findMsg(level, type_poi_warning);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendDuty_normal()
{
    const int ctype = type_duty_normal;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype);

    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = ctype;
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
        model->time = GTime::getUtcTime_s();
        model->msg = "值守预警报警";
    }
}

void MsgManage::cancelDuty_normal()
{
    const int ctype = type_duty_normal;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendDuty_emergency()
{
    const int ctype = type_duty_emergency;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype);

    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = ctype;
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
        model->time = GTime::getUtcTime_s();
        model->msg = "值守紧急报警";
    }
}

void MsgManage::cancelDuty_emergency()
{
    const int ctype = type_duty_emergency;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendRiskAreaWarning(int atype)
{
    const int ctype = type_riskarea;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype, atype);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = ctype;
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = -1;
        model->time = GTime::getUtcTime_s();
        model->voiceTime = 0;
        model->msg = "前方有风险区域";
        model->ID = atype;
        if (GLOG)
            GLOG->debug("MsgManage======RiskAreaWarning===================================={}", atype);
    }
}

void MsgManage::cancelRiskAreaWarning(int atype)
{
    const int ctype = type_riskarea;
    int level = getLevel(ctype);
    int index = findMsg(level, ctype, atype);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
        if (GLOG)
            GLOG->debug("MsgManage======cancelRiskAreaWarning====={}", atype);
    }
}

int MsgManage::getLevel(int type)
{
    return AlertLevel::alarm;
#if 0
    switch (type)
    {
    case type_device_recover:
    case type_poi_alarm:
    case type_poi_warning:
        case type_riskarea:
        return AlertLevel::caution; // 风险提示
    case type_device_lose:
    case type_shipCollision:
    case type_duty_emergency:
        return AlertLevel::alarm; // 紧急报警
    default:
        return AlertLevel::warning; // 预警报警
    }
#endif
}

/**
 * Finds a message in the given level and type.
 *
 * @param level the level of the message
 * @param type the type of the message
 * @param ID the ID of the message (optional)
 *
 * @return the index of the message if found, -1 otherwise
 *
 * @throws None
 */
int MsgManage::findMsg(int level, int type, qint64 ID)
{
    if (type == type_none)
        return -1;

    for (int i = 0, n = m_listMessage[level].count(); i < n; i++)
    {
        auto msg = m_listMessage[level].at(i);
        if (!msg->expired && msg->type == type && (ID == 0 || msg->ID == ID))
            return i;
    }
    return -1;
}

void MsgManage::getNext2Msg(int level, int &index1, int &index2)
{
    index1 = -1;
    index2 = -1;
    int n = m_listMessage[level].count();
    if (n == 0)
        return;
    // i==n，是再次判断当前model是否过期
    for (int i = 1; i <= n; i++)
    {
        int index = (m_msgIndex[level] + i) % n;
        auto msg = m_listMessage[level].at(index);
        if (!msg->expired && !msg->isEnsured)
        {
            index1 = index;
            break;
        }
    }
    m_msgIndex[level] = index1;
    if (n == 1 || index1 == -1)
        return;
    // 这里就不需要i==n的判断了
    for (int i = 1; i < n; i++)
    {
        int index = (index1 + i) % n;
        auto msg = m_listMessage[level].at(index);
        if (!msg->expired && !msg->isEnsured)
        {
            index2 = index;
            break;
        }
    }
}

ModelMsg *MsgManage::getNextMsg()
{
    if (m_deviceLost)
        return nullptr;
    const int level = AlertLevel::alarm;
    const int n = m_listMessage[level].count();
    ModelMsg *model1 = nullptr;
    int index1 = -1;
    qint64 ctime = GTime::getUtcTime_s();
    for (int i = 1; i <= n; i++)
    {
        index1 = (m_msgIndex[level] + i) % n;
        if (index1 < 0 || index1 >= n)
            continue;
        auto msg = m_listMessage[level].at(index1);
        if (msg->expired || msg->isEnsured)
            continue;
        if (msg->type == type_riskarea && (ctime - msg->voiceTime < 300)) // 风险区域5分钟播报一次
            continue;
        else if (msg->type == type_shipCollision && msg->voiceTimes >= 3 && (ctime - msg->voiceTime < 180)) // 船舶会遇，开始播报三次后三分钟播报一次
            continue;

        msg->voiceTime = ctime;
        model1 = msg.data();
        model1->voiceTimes++;
        break;
    }

    if (model1)
    {
        m_msgIndex[level] = index1;
        return model1;
    }
    else
    {
        m_msgIndex[level] = -1;
        return nullptr;
    }

#if 0
    // 取出预警报警中的下一条
    int level = AlertLevel::warning;
    int n = m_listMessage[level].size();
    ModelMsg *model1 = nullptr;
    int index1 = -1;
    if (n > 0)
    {
        for (int i = 1; i <= n; i++)
        {
            index1 = (m_msgIndex[level] + i) % n;
            auto msg = m_listMessage[level].at(index1);
            if (!msg->expired && !msg->isEnsured)
            {
                model1 = msg.data();
                break;
            }
        }
    }
    // 取出紧急报警中的下一条
    level = AlertLevel::alarm;
    n = m_listMessage[level].count();
    ModelMsg *model2 = nullptr;
    int index2 = -1;
    if (n > 0)
    {
        for (int i = 1; i <= n; i++)
        {
            index2 = (m_msgIndex[level] + i) % n;
            auto msg = m_listMessage[level].at(index2);
            if (!msg->expired && !msg->isEnsured)
            {
                model2 = msg.data();
                break;
            }
        }
    }

    // 按设计要求，预警报警和紧急报警，哪个的最新就返回哪个
    if (!model1)
    {
        if (model2)
        {
            m_msgIndex[AlertLevel::alarm] = index2;
            return model2;
        }
        else
            return nullptr;
    }
    if (!model2)
    {
        m_msgIndex[AlertLevel::warning] = index1;
        return model1;
    }
    if (model1->time < model2->time)
    {
        m_msgIndex[AlertLevel::alarm] = index2;
        return model2;
    }
    else
    {
        m_msgIndex[AlertLevel::warning] = index1;
        return model1;
    }
#endif
}

bool MsgManage::hasMsg() const
{
    if (m_deviceLost)
        return true;

    const int level = AlertLevel::alarm;
    const int n = m_listMessage[level].count();
    for (int i = 0; i < n; i++)
    {
        auto msg = m_listMessage[level].at(i);

        if (!msg->expired)
        {
            return true;
        }
    }
    return false;
}

ModelMsg *MsgManage::getNextCaution()
{
    int n = m_listMessage[AlertLevel::caution].count();
    int index = -1;
    ModelMsg *model = nullptr;
    for (int i = 1; i <= n; i++)
    {
        index = (m_msgIndex[AlertLevel::caution] + i) % n;
        auto msg = m_listMessage[AlertLevel::caution].at(index);
        if (!msg->expired && !msg->isEnsured)
        {
            model = msg.data();
            break;
        }
    }
    if (model)
    {
        m_msgIndex[AlertLevel::caution] = index;
        return model;
    }
    else
        return nullptr;
}

void MsgManage::save()
{
    DbAlertLog db;
    for (int level = 0; level < 3; level++)
    {
        int n = m_listMessage[level].count();
        for (int i = n - 1; i >= 0; i--)
        {
            auto msg = m_listMessage[level].at(i);
            if (msg->id == 0 || msg->expired)
            {
                bool posted = false;
                if (m_networkTask)
                {
                    if (msg->type == AlertType::type_device_lose)
                        posted = m_networkTask->postlog_system(3, msg->time);
                    else if (msg->type == AlertType::type_shipCollision)
                    {
                        if (msg->id == 0)
                            posted = m_networkTask->postlog_alert(3, msg->time, msg->ID);
                        if (msg->expired)
                            posted = m_networkTask->postlog_alert(4, msg->expiredTime, msg->ID);
                    }
                    else if (msg->type == AlertType::type_riskarea)
                    {
                        if (msg->id == 0)
                            posted = m_networkTask->postlog_alert(1, msg->time, msg->ID);
                        if (msg->expired)
                            posted = m_networkTask->postlog_alert(2, msg->expiredTime, msg->ID);
                    }
                }
                db.save(msg.data(), posted);
            }
            if (msg->expired)
            {
                m_listMessage[level].removeAt(i);
            }
        }
    }
}

void MsgManage::ensure(int level, int index, bool isEnsured)
{
    if (level < 0 || level > 2 || index < 0 || index >= m_listMessage[level].count())
        return;
    // if (m_audioOutput)
    // m_audioOutput->stop();
    auto msg = m_listMessage[level].at(index);
    msg->isEnsured = isEnsured;
    msg->ensureTime = GTime::getUtcTime_s();
    if (msg->type == type_shipCollision && !msg->expired)
    {
        // 下面的代码有问题：yhtc每次刷新船舶都是清空列表再新建，所以这里指针无法指向原来的船舶
        // ModelShip *ship = (msg->target.value<ModelShip *>());
        // if (ship)
        // {
        //     ship->dangerousEnsured = isEnsured;
        // }
        emit ensureToShipManage(msg->ID, isEnsured);
    }
}

void MsgManage::ensure(ModelMsg *model)
{
    if (!model)
        return;
    model->isEnsured = true;
    model->ensureTime = GTime::getUtcTime_s();
    GLOG->info("ensure message - {}", model->ID);
    if (model->type == type_shipCollision && !model->expired)
    {
        emit ensureToShipManage(model->ID, true);
    }
}

void MsgManage::ensure()
{
    for (int level = 0; level < 3; level++)
    {
        int n = m_listMessage[level].count();
        for (int i = 0; i < n; i++)
        {
            auto model = m_listMessage[level].at(i);
            model->isEnsured = true;
            model->ensureTime = GTime::getUtcTime_s();
            if (model->type == type_shipCollision && !model->expired)
            {
                emit ensureToShipManage(model->ID, true);
            }
        }
    }
}

void MsgManage::appendNearWaypoint(int wptindex)
{
    int level = getLevel(type_nearWaypoint);
    int index = findMsg(level, type_nearWaypoint);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_nearWaypoint;
        model->msg = QString("船舶接近航路点【WPT %1】").arg(wptindex, 3, 10, QChar('0'));
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::appendMeetWaypoint(int wptindex)
{
    int level = getLevel(type_nearWaypoint);
    int index = findMsg(level, type_nearWaypoint);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        model->msg = QString("船舶到达航路点【WPT %1】").arg(wptindex, 3, 10, QChar('0'));
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_nearWaypoint;
        model->msg = QString("船舶到达航路点【WPT %1】").arg(wptindex, 3, 10, QChar('0'));
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::appendNearDestination()
{
    int level = getLevel(type_nearDestination);
    int index = findMsg(level, type_nearDestination);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_nearDestination;
        model->msg = QString("船舶接近目的地");
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::appendMeetDestination()
{
    int level = getLevel(type_nearDestination);
    int index = findMsg(level, type_nearDestination);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        model->msg = QString("船舶到达目的地");
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_nearDestination;
        model->msg = QString("船舶到达目的地");
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::cancelNearWaypoint()
{
    int level = getLevel(type_nearWaypoint);
    int index = findMsg(level, type_nearWaypoint);
    if (index < 0)
        index = findMsg(level, type_nearDestination);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::appendUsermap()
{
    int level = getLevel(type_usermap);
    int index = findMsg(level, type_usermap);
    QSharedPointer<ModelMsg> model;
    if (index >= 0)
    {
        model = m_listMessage[level].at(index);
        m_msgIndex[level] = index;
        if (model->isEnsured)
            return;
    }
    else
    {
        model.reset(new ModelMsg);
        model->type = type_usermap;
        model->msg = QString("前方或周围有用户海图！");
        model->time = GTime::getUtcTime_s();
        m_listMessage[level].insert(0, model);
        m_msgIndex[level] = 0;
    }
    emit newMsg(model.data());
}

void MsgManage::cancelUsermap()
{
    int level = getLevel(type_usermap);
    int index = findMsg(level, type_usermap);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }
}

void MsgManage::timerEvent(QTimerEvent *event)
{
    save();
    if (m_networkTask)
        m_networkTask->postHeartbeat();
}

QString MsgManage::getLevelStr(int level)
{
    int type = getLevel(level);
    switch (type)
    {
    case 0:
        return "风险提示";
    case 1:
        return "预警报警";
    default:
        return "紧急报警";
    }
}

void MsgManage::appendDeviceLose(int deviceId)
{
    if (deviceId == DeviceType::Ais)
    {
        m_deviceLost = true;
        GLOG->info("AIS data lost!");
    }
#if 0
    QSharedPointer<ModelMsg> model(new ModelMsg);
    model->type = type_device_lose;
    model->msg = QString("[%1]数据丢失！").arg(getDeviceName(deviceId));
    model->ID = deviceId;
    model->time = GTime::getUtcTime_s();
    int level = getLevel(model->type);
    m_listMessage[level].insert(0, model);
    m_msgIndex[level] = 0;
    emit newMsg(model.data());
#endif
}

void MsgManage::recoverDevice(int deviceId)
{
    if (deviceId == DeviceType::Ais)
    {
        m_deviceLost = false;
        GLOG->info("AIS data recover!");
    }
#if 0
    int level = getLevel(type_device_lose);
    int index = findMsg(level, type_device_lose, deviceId);
    if (index >= 0)
    {
        auto model = m_listMessage[level].at(index);
        model->expired = true;
        model->expiredTime = GTime::getUtcTime_s();
    }

    level = getLevel(type_device_recover);
    QSharedPointer<ModelMsg> model(new ModelMsg);
    model->type = type_device_recover;
    model->msg = QString("[%1]数据恢复！").arg(getDeviceName(deviceId));
    model->ID = deviceId;
    model->time = GTime::getUtcTime_s();
    model->expiredTime = model->time + 30;
    m_listMessage[level].insert(0, model);
#endif
}

void MsgManage::setNetworkTask(NetworkTask *task)
{
    m_networkTask = task;
}